<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>13-async和await优化回调地狱问题</title>
</head>

<body>
  <!-- 
    async函数:
      1. 函数的返回值为 promise 对象 
      2. promise 对象的结果由 async 函数执行的返回值决定

    await表达式:
      1. await 右侧的表达式一般为 promise 对象, 但也可以是其它的值 
      2. 如果表达式是 promise 对象, await 返回的是 promise 成功的value 
      3. 如果表达式是其它值, 直接将此值作为 await 的返回值

    注意：
      1. 在非模块中，await 必须写在 async 函数中, 但 async 函数中可以没有 await 
      2. 如果 await 的 promise 失败了, 就会抛出异常, 需要通过 try...catch 捕获处理
      3. ES2022 开始，允许在模块的顶层（即模块的最外层作用域）独立使用`await`命令
   -->

  <script type="module">
    // 可复用的发 ajax 请求的函数: xhr + promise
    function sendAjax (url, data) {
      // 1. 创建并返回 Promise 实例对象(pending 状态), 指定执行器函数
      return new Promise((resolve, reject) => {
        // 2. 在执行器函数中启动异步任务
        console.log('异步任务启动---');
        // 3.发送ajax请求
        const xhr = new XMLHttpRequest();
        //处理query请求参数，将对象形式转成字符串
        let queryStr = '';
        for (const key in data)
        {
          queryStr += `?${key}=${data[key]}&`;
        }
        queryStr = queryStr.slice(0, -1);
        xhr.open('GET', url + queryStr);
        xhr.send();
        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4)
          {
            if (xhr.status >= 200 && xhr.status < 300)
            {
              // 请求成功, 调用 resolve(value)
              resolve(JSON.parse(xhr.response))
            } else
            {
              // 请求失败, 调用 reject(reason)
              reject(new Error('状态码：' + xhr.status))
            }
          }
        }
      })
    };
    //使用IIFE 立即调用函数表达式
    /* (
      async () => {
        try
        {
          const result1 = await sendAjax('https://api.github.com/search/users', { q: 'ajax' });
          console.log('第一次请求成功', result1);
          const result2 = await sendAjax('https://api.github.com/search/users11', { q: 'ajax' });
          console.log('第二次请求成功', result2);
          const result3 = await sendAjax('https://api.github.com/search/users', { q: 'ajax' });
          console.log('第三次请求成功', result3);
        } catch (error)
        {
          console.log('请求出了点问题', error);
        }
      }
    )(); */

    /* //测试 async 函数返回值
    async function demo () {
      console.log('111');
      return new Promise((resolve, reject) => {
        resolve('成功的value');
        console.log('22222');
      })
      // return Promise.reject(100)
    }
    console.log(demo());  //Promise {<pending>} */

    //测试在模块中顶层作用域中写 await ， 在 <script>标签中加上 type="module" 就可以指定代码块是模块
    try
    {
      const result1 = await sendAjax('https://api.github.com/search/users', { q: 'ajax' });
      console.log('第一次请求成功', result1);
      const result2 = await sendAjax('https://api.github.com/search/users11', { q: 'ajax' });
      console.log('第二次请求成功', result2);
      const result3 = await sendAjax('https://api.github.com/search/users', { q: 'ajax' });
      console.log('第三次请求成功', result3);
    } catch (error)
    {
      console.log('请求出了点问题', error);
    }

  </script>
</body>

</html>